package cn.cool.middleware.biz_exception_retry.config.processor;

import cn.cool.middleware.biz_exception_retry.config.registry.BeanMethodRegistry;
import cn.cool.middleware.biz_exception_retry.types.annotation.BizExceptionRetry;
import cn.cool.middleware.biz_exception_retry.types.exception.BizExceptionRetryException;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.util.ClassUtils;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * 业务异常重试的对象拦截，将所有需要业务重试的对象以 <[类名] -> [目标对象]> 的格式保存
 * 做定时重试的时候需要使用
 */
public class BizExceptionRetryObjectBeanPostProcessor implements BeanPostProcessor {
    private final BeanMethodRegistry beanMethodRegistry;

    public BizExceptionRetryObjectBeanPostProcessor(BeanMethodRegistry beanMethodRegistry) {
        this.beanMethodRegistry = beanMethodRegistry;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        Object targetBean = getOriginalBean(bean);

        Class<?> targetClass = targetBean.getClass();
        Method[] methods = targetClass.getDeclaredMethods();

        for (Method method : methods) {
            if (method.getDeclaringClass() == Object.class) continue;
            if (method.isAnnotationPresent(BizExceptionRetry.class)) {
                beanMethodRegistry.registerMethod(targetBean, method);
            }
        }
        return bean;
    }

    /** 获取原始Bean对象（非代理对象） */
    private Object getOriginalBean(Object bean) {
        // Spring 代理对象可能是 JDK 或 CGLIB 动态代理
        if (AopUtils.isAopProxy(bean)) {
            try {
                return AopProxyUtils.ultimateTargetClass(bean).cast(AopProxyUtils.getSingletonTarget(bean));
            } catch (Exception e) {
                // 若解析失败，返回原始 bean
                return bean;
            }
        }
        return bean;
    }
}
